package com.ziq.zcamp.manager

import android.annotation.SuppressLint
import android.provider.Settings
import android.util.Log
import android.widget.Toast
import androidx.lifecycle.MutableLiveData
import com.blankj.utilcode.util.GsonUtils
import com.gmlive.camp.data.exception.LocalException
import com.ziq.base.extension.launchWithTryAsyncGlobal
import com.ziq.base.manager.MMKVManager
import com.ziq.zcamp.R
import com.ziq.zcamp.api.request.camp.CampCollectParam
import com.ziq.zcamp.api.request.post.PostOperateParam
import com.ziq.zcamp.api.request.post.PostingLikeParam
import com.ziq.zcamp.api.request.post.PostingUnLikeParam
import com.ziq.zcamp.api.request.user.*
import com.ziq.zcamp.api.respond.CampBaseRespond
import com.ziq.zcamp.api.respond.user.PhoneLoginRespond
import com.ziq.zcamp.api.respond.user.UserFollowRelationRespond
import com.ziq.zcamp.api.respond.user.UserInfoRespond
import com.ziq.zcamp.api.respond.user.UserNumRelationRespond
import com.ziq.zcamp.api.service.*
import com.ziq.zcamp.bean.order.UserOrderStatisticsResult
import com.ziq.zcamp.bean.user.ImConf
import com.ziq.zcamp.bean.user.UserInfo
import com.ziq.zcamp.bean.user.UserMessageSessionList
import com.ziq.zcamp.constant.FollowRelation
import com.ziq.zcamp.constant.KEY_PHONE_LOGIN
import com.ziq.zcamp.constant.KEY_USER_INFO
import dagger.hilt.android.EntryPointAccessors
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext


class UserManager private constructor(){

    companion object {
        const val VISITOR_UID = 0
        val instance = SingletonHolder.holder
    }

    private object SingletonHolder {
        val holder= UserManager()
    }

    val isLogin = MutableLiveData<Boolean>()
    val phoneLogin = MutableLiveData<PhoneLoginRespond?>()
    val userInfo = MutableLiveData<UserInfo?>()

    //用户的订单信息待接单数
    val userOrderStatisticsInfo = MutableLiveData<UserOrderStatisticsResult?>()
    //关注
    val userFollowRelation = MutableLiveData<MutableMap<Int, String>>()
    //营地收藏
    val campCollect = MutableLiveData<MutableMap<Int, Int>>()
    //帖子点赞
    val postingLike = MutableLiveData<MutableMap<String, PostingLikeStatus>>()

    val imConf = MutableLiveData<ImConf?>()

    val newFansCountForMsgCenter = MutableLiveData<Int>() //消息中心 新粉丝 数量
    val praiseCountForMsgCenter = MutableLiveData<Int>()//消息中心 点赞 数量
    val commentCountForMsgCenter = MutableLiveData<Int>()//消息中心 评论 数量
    val userMessageSessionList = MutableLiveData<UserMessageSessionList?>()
    val updateImCountForMsgCenter = MutableLiveData<Boolean>()//IM消息 数量



    data class PostingLikeStatus(var num:Int, var isLike:Boolean)

    fun initCacheData(){
        try {
            val phoneLoginString = MMKVManager.mmkv.decodeString(KEY_PHONE_LOGIN, "")
            val item = GsonUtils.fromJson(phoneLoginString, PhoneLoginRespond::class.java)
            if(item != null){
                updatePhoneLogin(item)
            }
        }catch (e:Exception){}
        try {
            val userInfoString = MMKVManager.mmkv.decodeString(KEY_USER_INFO, "")
            val item = GsonUtils.fromJson(userInfoString, UserInfo::class.java)
            if(item != null){
                userInfo.value = item
            }
        }catch (e:Exception){}
    }

    fun updatePhoneLogin(item: PhoneLoginRespond?){
        isLogin.value = true
        phoneLogin.value = item
        MMKVManager.mmkv.encode(KEY_PHONE_LOGIN, GsonUtils.toJson(item))
        onLogin()
    }

    fun logout(){
        isLogin.value = false
        onLogout()
    }


    private fun onLogin(){
        //长连接登录
        Log.i("wyq", "onLogin")
        LongLinkManager.instance.connect()
    }

    private fun onLogout(){
        MMKVManager.mmkv.remove(KEY_PHONE_LOGIN)
        MMKVManager.mmkv.remove(KEY_USER_INFO)
        phoneLogin.value = null
        userInfo.value = null
        MerchantManager.instance.userCurrentCampInfo.value = null
        MerchantManager.instance.orderStatisticsInfo.value = null
        MerchantManager.instance.allCampStatisticsInfo.value = null
        userOrderStatisticsInfo.value = null
        userFollowRelation.postValue(mutableMapOf<Int, String>())
        postingLike.postValue(mutableMapOf())
        campCollect.postValue(mutableMapOf())
        userMessageSessionList.value = null
        newFansCountForMsgCenter.value = 0
        praiseCountForMsgCenter.value = 0
        commentCountForMsgCenter.value = 0
        DataManager.increasePostingListVersion()

        LongLinkManager.instance.disconnect()

    }

    fun requestUserInfo(uid: Int,
                        onSuccess: ((result: UserInfoRespond) -> Unit)? = {
                            updateUserInfo(it.data)
                        },
                        onFail: ((result: String) -> Unit)? = {}) {

        launchWithTryAsyncGlobal(whenTry = {
            val entryPoint = EntryPointAccessors.fromApplication(
                GlobalContextManager.appContext!!,
                ServiceEntryPointManager::class.java
            )
            val respond = entryPoint.userAccountService().userInfo(UserInfoParam().apply {
                this.uid = uid
            }).request()
            withContext(Dispatchers.Main){
                respond?.let {
                    onSuccess?.invoke(it)
                }
            }
        }, whenCatch = {
            withContext(Dispatchers.Main){
                onFail?.invoke("$it")
            }
        })
    }

    fun updateUserInfo(item: UserInfo?){
        if(item != null){
            userInfo.value = item
            MMKVManager.mmkv.encode(KEY_USER_INFO, GsonUtils.toJson(item))
        }
    }


    fun getAtomMap() : Map<String, Any?> {
        val result = mutableMapOf<String, Any?>()
        result["cv"] = "CAMP3.22.00_Android"
        getUid().let {
            if(it != UserManager.VISITOR_UID){
                result["uid"] = it.toString()
            }
        }
        result["sid"] = getSid()
        result["smid"] = getAndroidId() //1417088f20f36588
        return result
    }



    fun getUid() : Int{
        if(phoneLogin.value != null && phoneLogin.value?.data?.uid != null){
            return phoneLogin.value?.data?.uid!!
        }
        return VISITOR_UID
    }

    fun getSid() : String{
        if(phoneLogin.value != null && phoneLogin.value?.data?.uid != null){
            return phoneLogin.value?.data?.sid!!
        }
        return ""
    }

    @SuppressLint("HardwareIds")
    fun getAndroidId(): String {
        return Settings.Secure.getString(GlobalContextManager.appContext?.contentResolver, Settings.Secure.ANDROID_ID)
    }

    fun isMine(uid : Int) :Boolean{
        if(isLogin.value == true && uid == getUid()){
            return true
        }
        return false
    }


    fun collectCamp(campid : Int, status : Int,
                    onSuccessAction: ((result: CampBaseRespond) -> Unit)? = {},
                    onSuccess: ((result: CampBaseRespond) -> Unit)? = {
                        if(status == 0){
                            val msg = GlobalContextManager.getString(R.string.collect_success)
                            Toast.makeText(GlobalContextManager.appContext!!, msg, Toast.LENGTH_SHORT).show()
                        } else {
                            val msg = GlobalContextManager.getString(R.string.un_collect_success)
                            Toast.makeText(GlobalContextManager.appContext!!, msg, Toast.LENGTH_SHORT).show()
                        }
                    },
                    onFail: ((result: String) -> Unit)? = {
                        if(status == 0){
                            updateUnCollectCamp(campid)
                        } else {
                            updateCollectCamp(campid)
                        }
                        Toast.makeText(GlobalContextManager.appContext!!, it, Toast.LENGTH_SHORT).show()
                    }) {
        if(status == 0){
            updateCollectCamp(campid)
        } else {
            updateUnCollectCamp(campid)
        }

        launchWithTryAsyncGlobal(whenTry = {
            val entryPoint = EntryPointAccessors.fromApplication(
                GlobalContextManager.appContext!!,
                ServiceEntryPointManager::class.java
            )
            val respond = entryPoint.campService().campCollectStatusUpdate(CampCollectParam().apply {
                this.campid = campid
                this.status = status
            }).request()
            withContext(Dispatchers.Main){
                if(respond != null){
                    if (respond.isSuccess){
                        onSuccess?.invoke(respond)
                        onSuccessAction?.invoke(respond)
                    }else{
                        onFail?.invoke(respond.errorMsg?:"网络异常")
                    }
                }
            }
        }, whenCatch = {
            withContext(Dispatchers.Main) {
                when (it) {
                    is NetWorkException -> {
                        it.printStackTrace()
                    }
                    is LocalException -> {
                        it.printStackTrace()
                    }
                }
            }
        })

    }

    fun updateCollectCamp(campid : Int){
        val temp = campCollect.value ?: mutableMapOf<Int, Int>()
        temp[campid] = 0
        campCollect.postValue(temp)
    }

    fun updateUnCollectCamp(campid : Int){
        val temp = campCollect.value ?: mutableMapOf<Int, Int>()
        temp[campid] = 1
        campCollect.postValue(temp)
    }


    fun likePosting(post_id : String, create_uid : Int, count: Int,
                    onSuccess: ((result: CampBaseRespond) -> Unit)? = {},
                    onFail: ((result: String) -> Unit)? = {}) {
        launchWithTryAsyncGlobal(whenTry = {

            val entryPoint = EntryPointAccessors.fromApplication(
                GlobalContextManager.appContext!!,
                ServiceEntryPointManager::class.java
            )
            val respond = entryPoint.postingService().postingLike(PostingLikeParam().apply {
                this.post_id = post_id
                this.create_uid = create_uid.toString()
            }).request()

            withContext(Dispatchers.Main){
                respond?.let {
                    onSuccess?.invoke(it)
                }
            }
            val temp = postingLike.value ?: mutableMapOf()
            if(temp.containsKey(post_id)){
                temp[post_id]?.let { status ->
                    status.num = status.num + 1
                    status.isLike = true
                }
            } else {
                temp[post_id] = PostingLikeStatus(count, true)
            }
            postingLike.postValue(temp)
        }, whenCatch = {
            withContext(Dispatchers.Main){
                onFail?.invoke("$it")
            }
        })
    }

    fun unlikePosting(post_id : String, create_uid : Int, count: Int,
                      onSuccess: ((result: CampBaseRespond) -> Unit)? = {},
                      onFail: ((result: String) -> Unit)? = {}) {

        launchWithTryAsyncGlobal(whenTry = {

            val entryPoint = EntryPointAccessors.fromApplication(
                GlobalContextManager.appContext!!,
                ServiceEntryPointManager::class.java
            )
            val respond = entryPoint.postingService().postingUnLike(PostingUnLikeParam().apply {
                this.post_id = post_id
                this.create_uid = create_uid.toString()
            }).request()

            withContext(Dispatchers.Main){
                respond?.let {
                    onSuccess?.invoke(it)
                }
            }
            val temp = postingLike.value ?: mutableMapOf()
            if(temp.containsKey(post_id)){
                temp[post_id]?.let { status ->
                    if(status.num > 0){
                        status.num = status.num - 1
                    }
                    status.isLike = false
                }
            } else {
                temp[post_id] = PostingLikeStatus(count, false)
            }
            postingLike.postValue(temp)
        }, whenCatch = {
            withContext(Dispatchers.Main){
                onFail?.invoke("$it")
            }
        })
    }


    fun getNumRelation(uid: Int, onSuccess: ((result: UserNumRelationRespond) -> Unit)? = {
    },
                       onFail: ((result: String) -> Unit)? = {
                           Toast.makeText(GlobalContextManager.appContext!!, it, Toast.LENGTH_SHORT).show()
                       }) {

        launchWithTryAsyncGlobal(whenTry = {
            val entryPoint = EntryPointAccessors.fromApplication(
                GlobalContextManager.appContext!!,
                ServiceEntryPointManager::class.java
            )
            val respond = entryPoint.userAccountService().userNumRelation(UserNumRelationParam().apply {
                this.id = uid
            }.queryMap).request()

            withContext(Dispatchers.Main){
                onSuccess?.invoke(respond)
            }
        }, whenCatch = {
            withContext(Dispatchers.Main){
                onFail?.invoke("$it")
            }
        })
    }

    fun followUser(followedUid : Int,
                   onSuccess: ((result: CampBaseRespond) -> Unit)? = {
                       val msg = GlobalContextManager.getString(R.string.follow_success)
                       Toast.makeText(GlobalContextManager.appContext!!, msg, Toast.LENGTH_SHORT).show()
                       DataManager.increaseFollowStatusVersion()
                   },
                   onFail: ((result: String) -> Unit)? = {
                       updateFollowRelationForUnFollow(followedUid)
                       Toast.makeText(GlobalContextManager.appContext!!, it, Toast.LENGTH_SHORT).show()
                   }) {
        updateFollowRelationForFollow(followedUid)

        launchWithTryAsyncGlobal(whenTry = {
            val entryPoint = EntryPointAccessors.fromApplication(
                GlobalContextManager.appContext!!,
                ServiceEntryPointManager::class.java
            )
            val respond = entryPoint.userAccountService().userFollow(UserFollowParam().apply {
                this.uid = getUid()
                this.id = followedUid
            }.queryMap).request()

            withContext(Dispatchers.Main){
                onSuccess?.invoke(respond)
            }
        }, whenCatch = {
            withContext(Dispatchers.Main){
                onFail?.invoke("$it")
            }
        })
    }

    fun unfollowUser(followedUid : Int,
                     onSuccess: ((result: CampBaseRespond) -> Unit)? = {
                         val msg = GlobalContextManager.getString(R.string.un_follow_success)
                         Toast.makeText(GlobalContextManager.appContext!!, msg, Toast.LENGTH_SHORT).show()
                         DataManager.increaseFollowStatusVersion()
                     },
                     onFail: ((result: String) -> Unit)? = {
                         updateFollowRelationForFollow(followedUid)
                         Toast.makeText(GlobalContextManager.appContext!!, it, Toast.LENGTH_SHORT).show()
                     }) {
        updateFollowRelationForUnFollow(followedUid)

        launchWithTryAsyncGlobal(whenTry = {
            val entryPoint = EntryPointAccessors.fromApplication(
                GlobalContextManager.appContext!!,
                ServiceEntryPointManager::class.java
            )
            val respond = entryPoint.userAccountService().userUnFollow(UserUnFollowParam().apply {
                this.uid = getUid()
                this.id = followedUid
            }.queryMap).request()

            withContext(Dispatchers.Main){
                onSuccess?.invoke(respond)
            }
        }, whenCatch = {
            withContext(Dispatchers.Main){
                onFail?.invoke("$it")
            }
        })
    }

    fun updateFollowRelationForFollow(followedUid : Int){
        val temp = userFollowRelation.value ?: mutableMapOf<Int, String>()
        if(temp[followedUid] == FollowRelation.befollow.value){
            temp[followedUid] = FollowRelation.mutual.value
        } else {
            temp[followedUid] = FollowRelation.following.value
        }
        userFollowRelation.postValue(temp)
    }

    fun updateFollowRelationForUnFollow(followedUid : Int){
        val temp = userFollowRelation.value ?: mutableMapOf<Int, String>()
        if(temp[followedUid] == FollowRelation.mutual.value){
            temp[followedUid] = FollowRelation.befollow.value
        } else if(temp[followedUid] == FollowRelation.following.value){
            temp[followedUid] = FollowRelation.none.value
        }
        userFollowRelation.postValue(temp)
    }

    fun getFollowRelation(followedUid : Int,
                          onSuccess: ((result: UserFollowRelationRespond) -> Unit)? = {
                              if(it.data != null){
                                  val temp = userFollowRelation.value ?: mutableMapOf<Int, String>()
                                  temp[followedUid] = it.data!!
                                  userFollowRelation.postValue(temp)
                              }
                          },
                          onFail: ((result: String) -> Unit)? = {}) {


        launchWithTryAsyncGlobal(whenTry = {
            val entryPoint = EntryPointAccessors.fromApplication(
                GlobalContextManager.appContext!!,
                ServiceEntryPointManager::class.java
            )
            val respond = entryPoint.userAccountService().userFollowRelation(UserFollowRelationParam().apply {
                this.uid = getUid()
                this.id = followedUid
            }.queryMap).request()

            withContext(Dispatchers.Main){
                onSuccess?.invoke(respond)
            }
        }, whenCatch = {
            withContext(Dispatchers.Main){
                onFail?.invoke("$it")
            }
        })
    }

    fun isPostAdministration():Boolean{
        if (userInfo.value == null)return false
        return userInfo.value?.is_post_admin?:false
    }

    fun adminRemovePost(postId :String , uid :Int,
                        onSuccess: (() -> Unit)? = {

                        },
                        onFail: ((result: String) -> Unit)? = {

                        }) {
        if (!isPostAdministration()){
            return
        }

        launchWithTryAsyncGlobal(whenTry = {
            val entryPoint = EntryPointAccessors.fromApplication(
                GlobalContextManager.appContext!!,
                ServiceEntryPointManager::class.java
            )
            val respond = entryPoint.postingService().postOperate(PostOperateParam().apply {
                this.post_id = postId
                this.post_status = 2
                this.uid = uid
            }).request()
            withContext(Dispatchers.Main){
                onSuccess?.invoke()
            }
        }, whenCatch = {
            withContext(Dispatchers.Main){
                onFail?.invoke("$it")
            }
        })
    }

}

